package edu.zju.gis.dbfg.fileserver.util.reader;


import edu.zju.gis.dbfg.common.exception.DataReaderException;
import edu.zju.gis.dbfg.common.exception.DataReaderExceptionEnum;
import edu.zju.gis.dbfg.fileserver.model.FieldInfo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.dbf.DbaseFileHeader;
import org.geotools.data.shapefile.dbf.DbaseFileReader;
import org.geotools.data.shapefile.files.ShpFiles;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.GeometryAttribute;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.charset.Charset;

import static edu.zju.gis.dbfg.fileserver.common.Seprator.TAB;
import static edu.zju.gis.dbfg.fileserver.common.Seprator.SINGLE_LINE;

/**
 * @author Hu
 * @date 2019/6/19
 **/
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class ShpFileReader extends DataReader {

    private static final Logger logger = LoggerFactory.getLogger(ShpFileReader.class);

    private FeatureIterator<SimpleFeature> reader;

    @Override
    public void init() {
        super.init();
        this.initReader();
        this.readHeader();
    }

    private void initReader() {
        File file = new File(filename);
        if (!file.exists()) {
            throw new DataReaderException(DataReaderExceptionEnum.FILE_NOT_EXIST, this.filename);
        }
        try {
            ShapefileDataStore shpDataStore = new ShapefileDataStore(file.toURI().toURL());
            //设置编码
            Charset charset = Charset.forName("utf8");
            shpDataStore.setCharset(charset);
            String typeName = shpDataStore.getTypeNames()[0]; // 获取第一层图层名
            SimpleFeatureSource featureSource = shpDataStore.getFeatureSource(typeName);
            FeatureCollection<SimpleFeatureType, SimpleFeature> collection = featureSource.getFeatures();
            this.reader = collection.features();
        } catch (MalformedURLException e) {
            e.printStackTrace();
            throw new DataReaderException(DataReaderExceptionEnum.SYSTEM_READ_ERROR, this.filename);
        } catch (IOException e) {
            e.printStackTrace();
            throw new DataReaderException(DataReaderExceptionEnum.SYSTEM_READ_ERROR, this.filename);
        }
    }

    @Override
    public String next() {
        return reader.hasNext() ? featureToWKT(reader.next(), this.headers) : null;
    }

    /**
     * 获取文件头信息
     *
     * @return 由header的名字组成的字符串数组
     * @throws Exception
     */
    @Override
    protected String[] readHeader() {
        if (this.headers != null) return this.headers;
        try {
            DbaseFileReader reader = new DbaseFileReader(new ShpFiles(this.filename), false, Charset.forName("utf8"));
            DbaseFileHeader header = reader.getHeader();
            int numFields = header.getNumFields();
            String[] results = new String[numFields];
            for (int i = 0; i < numFields; i++) {
                results[i] = header.getFieldName(i);
            }
            this.headers = results;
            reader.close();
            return this.headers;
        } catch (IOException e) {
            e.printStackTrace();
            throw new DataReaderException(DataReaderExceptionEnum.SYSTEM_READ_ERROR, this.filename);
        }
    }

    @Override
    public void close() {
        if (reader != null) reader.close();
    }

    private String featureToWKT(SimpleFeature feature, String[] headers) {
        StringBuilder sb = new StringBuilder();
//        sb.append(feature.getID().substring(feature.getID().lastIndexOf(".") + 1) + TAB.getValue());
        for (String header : headers) {
            sb.append(String.valueOf(feature.getAttribute(header)) + TAB.getValue());
        }
        // 此行输出的空间信息的wkt表达形式
        sb.append(feature.getDefaultGeometryProperty().getValue());
        sb.append(SINGLE_LINE.getValue());
        return sb.toString();
    }

    public FieldInfo[] getHeaderInfo() {
        try {
            DbaseFileReader reader = new DbaseFileReader(new ShpFiles(this.filename), false, Charset.forName("GBK"));
            DbaseFileHeader header = reader.getHeader();
            int numFields = header.getNumFields();
            FieldInfo[] results = new FieldInfo[numFields];
            for (int i = 0; i < numFields; i++) {
                FieldInfo item = new FieldInfo();
                item.setName(header.getFieldName(i));
                item.setType(header.getFieldClass(i).getSimpleName());
                item.setLength(header.getFieldLength(i));
                item.setDecimal(header.getFieldDecimalCount(i));
                results[i] = item;
            }
            reader.close();
            return results;
        } catch (IOException e) {
            e.printStackTrace();
            throw new DataReaderException(DataReaderExceptionEnum.SYSTEM_READ_ERROR, this.filename);
        }
    }

    public String getShpType() {
        GeometryAttribute temp = this.reader.next().getDefaultGeometryProperty();
        return temp.getType().getName().toString();
    }
}
